package name.panitz.ludens.strategy;
import java.util.*;
import java.io.*;
class Muehle extends AbstractRegularGame<Move>{
  byte playerStartStones [] = {9,9};
  byte playerStones [] = {9,9};

  Muehle prevState=null;

  Muehle(){
    super((byte)3,(byte)8);
  }

  public Muehle setAtPosition(byte column,byte row){
    throw new UnsupportedOperationException();
  }
  public byte getAtPosition(byte column,byte row){
    return b[column][row];
  }

  byte atPos(Position p){return b[p.triblet][p.pos];}

  public List<Move> moves(){
    final List<Move> result = new LinkedList<Move>();
    //first move
    if (movesDone==0){
      result.add(new Set((byte)1,(byte)0));
      result.add(new Set((byte)2,(byte)0));
      result.add(new Set((byte)1,(byte)1));
      result.add(new Set((byte)2,(byte)1));
      return result;
    }

    final List<SetStone> myStones = new LinkedList<SetStone>();
    //StartGame
    if (playerStartStones[player%2]>0){
      for (byte trs=0;trs<columns;trs++){
        for (byte pos=0;pos<rows;pos++){
          if (b[trs][pos]==getPlayerNone()){
            myStones.add(new Set(trs,pos));
          }
	}
      }
      //MiddleGame
    }else if (playerStones[player%2]>3){
      for (byte trs=0;trs<columns;trs++){
        for (byte pos=0;pos<rows;pos++){
          if (b[trs][pos]==player){
            Position from= new Position(trs,pos);
	    for (Position to:from.connectedPositions()){
	      if (b[to.triblet][to.pos]==NONE){
                myStones.add(new MoveStone(from,to));
	      }
	    }
	  }
	}
      }
      //Endgame
    }else{
      for (byte trs=0;trs<columns;trs++){
        for (byte pos=0;pos<rows;pos++){
          final Position from = new Position(trs,pos);
          if (player==atPos(from)){
	    for (byte trs2=0;trs<columns;trs++){
	      for (byte pos2=0;pos<rows;pos++){
		final Position to = new Position(trs2,pos2);
		if (Muehle.NONE==atPos(to)){
                  myStones.add(new MoveStone(from,to));
                }
	      }
	    }
	  }
	}
      }
    }
    //Remove if Muehle!
    for (SetStone myStone:myStones){
      Position p=myStone.getPosition();
      final Muehle m=(Muehle)this.doMove(myStone);
      if (!m.inMuehle(p))result.add(myStone);
      else {
        for (Position take:stonesToTake(nextPlayer())){
          result.add(new Remove(myStone,take));
        }
      }
    }

    return result;
  }

  boolean inMuehle(Position p){
    byte c = atPos(p);
    for (Position[] row:p.rows()){
      int sum = atPos(row[0])+atPos(row[1])+atPos(row[2]); 
      if (sum==3*c) return true;
    }
    return false;
  }

  List<Position> stonesToTake(byte pl){
    final List<Position> result = new LinkedList<Position>();      
    for (byte c=0;c<columns;c++){
      for (byte r=0;r<rows;r++){
        Position p=new Position(c,r);
        if (b[c][r]==pl&&!inMuehle(p))
	    result.add(p);
      }
    }
    return result;
  }

  @Override
  public Muehle clone(){
    final Muehle result = (Muehle)super.clone();
    result.playerStartStones=playerStartStones.clone();
    result.playerStones=playerStones.clone();
    return result;
  }

  public Muehle doMove(Move m){
    Muehle result= m.move(this);
    result.prevState=this;
    return result;
  }

  int sum(int a1,int a2,int b1,int b2,int c1,int c2){
    return b[a1][a2]+b[b1][b2]+b[c1][c2];
  }

  int evalRow(int a1,int a2,int b1,int b2,int c1,int c2
             ,byte player){
     int s =sum(a1,a2,b1,b2,c1,c2);
     if (s==2*player+NONE) return 10;
     if (s==2*otherPlayer(player)+NONE) return -10;
     return 0;
   }

  public int evalState(byte player){
    int result=(playerStones[player%2]
               -playerStones[otherPlayer(player)%2])*1000;
    result=result+evalRow(0,0,0,1,0,2,player);
    result=result+evalRow(0,2,0,3,0,4,player);
    result=result+evalRow(0,4,0,5,0,6,player);
    result=result+evalRow(0,6,0,7,0,0,player);

    result=result+evalRow(1,0,1,1,1,2,player);
    result=result+evalRow(1,2,1,3,1,4,player);
    result=result+evalRow(1,4,1,5,1,6,player);
    result=result+evalRow(1,6,1,7,1,0,player);

    result=result+evalRow(2,0,2,1,2,2,player);
    result=result+evalRow(2,2,2,3,2,4,player);
    result=result+evalRow(2,4,2,5,2,6,player);
    result=result+evalRow(2,6,2,7,2,0,player);

    result=result+evalRow(0,1,1,1,2,1,player);
    result=result+evalRow(0,3,1,3,2,3,player);
    result=result+evalRow(0,5,1,5,2,5,player);
    result=result+evalRow(0,7,1,7,2,7,player);
    return result;
  }

  public boolean wins(byte p){return playerStones[p%2]==2;}
  public boolean noMoreMove(){return moves().isEmpty();}

  @Override
  public String toString(){
    final StringBuffer result=new StringBuffer();
    for (int r=rows-1;r>=0;r--){
      for (int c=0;c<columns;c++) result.append(""+b[c][r]);
      result.append("\n");
    }
    return result+"";
  }
}

